<!-- HTML header for doxygen 1.8.6-->
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/xhtml;charset=UTF-8"/>
<meta http-equiv="X-UA-Compatible" content="IE=9"/>
<meta name="generator" content="Doxygen 1.8.13"/>
<title>OpenCV: Feature Matching with FLANN</title>
<link href="../../opencv.ico" rel="shortcut icon" type="image/x-icon" />
<link href="../../tabs.css" rel="stylesheet" type="text/css"/>
<script type="text/javascript" src="../../jquery.js"></script>
<script type="text/javascript" src="../../dynsections.js"></script>
<script type="text/javascript" src="../../tutorial-utils.js"></script>
<link href="../../search/search.css" rel="stylesheet" type="text/css"/>
<script type="text/javascript" src="../../search/searchdata.js"></script>
<script type="text/javascript" src="../../search/search.js"></script>
<script type="text/x-mathjax-config">
  MathJax.Hub.Config({
    extensions: ["tex2jax.js", "TeX/AMSmath.js", "TeX/AMSsymbols.js"],
    jax: ["input/TeX","output/HTML-CSS"],
});
//<![CDATA[
MathJax.Hub.Config(
{
  TeX: {
      Macros: {
          matTT: [ "\\[ \\left|\\begin{array}{ccc} #1 & #2 & #3\\\\ #4 & #5 & #6\\\\ #7 & #8 & #9 \\end{array}\\right| \\]", 9],
          fork: ["\\left\\{ \\begin{array}{l l} #1 & \\mbox{#2}\\\\ #3 & \\mbox{#4}\\\\ \\end{array} \\right.", 4],
          forkthree: ["\\left\\{ \\begin{array}{l l} #1 & \\mbox{#2}\\\\ #3 & \\mbox{#4}\\\\ #5 & \\mbox{#6}\\\\ \\end{array} \\right.", 6],
          forkfour: ["\\left\\{ \\begin{array}{l l} #1 & \\mbox{#2}\\\\ #3 & \\mbox{#4}\\\\ #5 & \\mbox{#6}\\\\ #7 & \\mbox{#8}\\\\ \\end{array} \\right.", 8],
          vecthree: ["\\begin{bmatrix} #1\\\\ #2\\\\ #3 \\end{bmatrix}", 3],
          vecthreethree: ["\\begin{bmatrix} #1 & #2 & #3\\\\ #4 & #5 & #6\\\\ #7 & #8 & #9 \\end{bmatrix}", 9],
          cameramatrix: ["#1 = \\begin{bmatrix} f_x & 0 & c_x\\\\ 0 & f_y & c_y\\\\ 0 & 0 & 1 \\end{bmatrix}", 1],
          distcoeffs: ["(k_1, k_2, p_1, p_2[, k_3[, k_4, k_5, k_6 [, s_1, s_2, s_3, s_4[, \\tau_x, \\tau_y]]]]) \\text{ of 4, 5, 8, 12 or 14 elements}"],
          distcoeffsfisheye: ["(k_1, k_2, k_3, k_4)"],
          hdotsfor: ["\\dots", 1],
          mathbbm: ["\\mathbb{#1}", 1],
          bordermatrix: ["\\matrix{#1}", 1]
      }
  }
}
);
//]]>
</script><script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.0/MathJax.js"></script>
<link href="../../doxygen.css" rel="stylesheet" type="text/css" />
<link href="../../stylesheet.css" rel="stylesheet" type="text/css"/>
</head>
<body>
<div id="top"><!-- do not remove this div, it is closed by doxygen! -->
<div id="titlearea">
<!--#include virtual="/google-search.html"-->
<table cellspacing="0" cellpadding="0">
 <tbody>
 <tr style="height: 56px;">
  <td id="projectlogo"><img alt="Logo" src="../../opencv-logo-small.png"/></td>
  <td style="padding-left: 0.5em;">
   <div id="projectname">OpenCV
   &#160;<span id="projectnumber">4.5.2</span>
   </div>
   <div id="projectbrief">Open Source Computer Vision</div>
  </td>
 </tr>
 </tbody>
</table>
</div>
<!-- end header part -->
<!-- Generated by Doxygen 1.8.13 -->
<script type="text/javascript">
var searchBox = new SearchBox("searchBox", "../../search",false,'Search');
</script>
<script type="text/javascript" src="../../menudata.js"></script>
<script type="text/javascript" src="../../menu.js"></script>
<script type="text/javascript">
$(function() {
  initMenu('../../',true,false,'search.php','Search');
  $(document).ready(function() { init_search(); });
});
</script>
<div id="main-nav"></div>
<!-- window showing the filter options -->
<div id="MSearchSelectWindow"
     onmouseover="return searchBox.OnSearchSelectShow()"
     onmouseout="return searchBox.OnSearchSelectHide()"
     onkeydown="return searchBox.OnSearchSelectKey(event)">
</div>

<!-- iframe showing the search results (closed by default) -->
<div id="MSearchResultsWindow">
<iframe src="javascript:void(0)" frameborder="0" 
        name="MSearchResults" id="MSearchResults">
</iframe>
</div>

<div id="nav-path" class="navpath">
  <ul>
<li class="navelem"><a class="el" href="../../d9/df8/tutorial_root.html">OpenCV Tutorials</a></li><li class="navelem"><a class="el" href="../../d9/d97/tutorial_table_of_content_features2d.html">2D Features framework (feature2d module)</a></li>  </ul>
</div>
</div><!-- top -->
<div class="header">
  <div class="headertitle">
<div class="title">Feature Matching with FLANN </div>  </div>
</div><!--header-->
<div class="contents">
<div class="textblock"><p><b>Prev Tutorial:</b> <a class="el" href="../../d5/dde/tutorial_feature_description.html">Feature Description</a></p>
<p><b>Next Tutorial:</b> <a class="el" href="../../d7/dff/tutorial_feature_homography.html">Features2D + Homography to find a known object</a></p>
<table class="doxtable">
<tr>
<th align="right"></th><th align="left"></th></tr>
<tr>
<td align="right">Original author </td><td align="left">Ana Huamán </td></tr>
<tr>
<td align="right">Compatibility </td><td align="left">OpenCV &gt;= 3.0 </td></tr>
</table>
<h2>Goal </h2>
<p>In this tutorial you will learn how to:</p>
<ul>
<li>Use the <a class="el" href="../../dc/de2/classcv_1_1FlannBasedMatcher.html">cv::FlannBasedMatcher</a> interface in order to perform a quick and efficient matching by using the <a class="el" href="../../dc/de5/group__flann.html">Clustering and Search in Multi-Dimensional Spaces</a> module</li>
</ul>
<dl class="section warning"><dt>Warning</dt><dd>You need the <a href="https://github.com/opencv/opencv_contrib">OpenCV contrib modules</a> to be able to use the SURF features (alternatives are ORB, KAZE, ... features).</dd></dl>
<h2>Theory </h2>
<p>Classical feature descriptors (SIFT, SURF, ...) are usually compared and matched using the Euclidean distance (or L2-norm). Since SIFT and SURF descriptors represent the histogram of oriented gradient (of the Haar wavelet response for SURF) in a neighborhood, alternatives of the Euclidean distance are histogram-based metrics ( \( \chi^{2} \), Earth Mover’s Distance (EMD), ...).</p>
<p>Arandjelovic et al. proposed in <a class="el" href="../../d0/de3/citelist.html#CITEREF_Arandjelovic:2012:TTE:2354409.2355123">[12]</a> to extend to the RootSIFT descriptor: </p><blockquote class="doxtable">
<p>a square root (Hellinger) kernel instead of the standard Euclidean distance to measure the similarity between SIFT descriptors leads to a dramatic performance boost in all stages of the pipeline. </p>
</blockquote>
<p>Binary descriptors (ORB, BRISK, ...) are matched using the <a href="https://en.wikipedia.org/wiki/Hamming_distance">Hamming distance</a>. This distance is equivalent to count the number of different elements for binary strings (population count after applying a XOR operation): </p><p class="formulaDsp">
\[ d_{hamming} \left ( a,b \right ) = \sum_{i=0}^{n-1} \left ( a_i \oplus b_i \right ) \]
</p>
<p>To filter the matches, Lowe proposed in <a class="el" href="../../d0/de3/citelist.html#CITEREF_Lowe04">[154]</a> to use a distance ratio test to try to eliminate false matches. The distance ratio between the two nearest matches of a considered keypoint is computed and it is a good match when this value is below a threshold. Indeed, this ratio allows helping to discriminate between ambiguous matches (distance ratio between the two nearest neighbors is close to one) and well discriminated matches. The figure below from the SIFT paper illustrates the probability that a match is correct based on the nearest-neighbor distance ratio test.</p>
<div class="image">
<img src="../../Feature_FlannMatcher_Lowe_ratio_test.png" alt="Feature_FlannMatcher_Lowe_ratio_test.png"/>
</div>
<p>Alternative or additional filterering tests are:</p><ul>
<li>cross check test (good match \( \left( f_a, f_b \right) \) if feature \( f_b \) is the best match for \( f_a \) in \( I_b \) and feature \( f_a \) is the best match for \( f_b \) in \( I_a \))</li>
<li>geometric test (eliminate matches that do not fit to a geometric model, e.g. RANSAC or robust homography for planar objects)</li>
</ul>
<h2>Code </h2>
 <div class='newInnerHTML' title='cpp' style='display: none;'>C++</div><div class='toggleable_div label_cpp' style='display: none;'><p> This tutorial code's is shown lines below. You can also download it from <a href="https://github.com/opencv/opencv/tree/master/samples/cpp/tutorial_code/features2D/feature_flann_matcher/SURF_FLANN_matching_Demo.cpp">here</a> </p><div class="fragment"><div class="line"><span class="preprocessor">#include &lt;iostream&gt;</span></div><div class="line"><span class="preprocessor">#include &quot;<a class="code" href="../../d0/d9c/core_2include_2opencv2_2core_8hpp.html">opencv2/core.hpp</a>&quot;</span></div><div class="line"><span class="preprocessor">#ifdef HAVE_OPENCV_XFEATURES2D</span></div><div class="line"><span class="preprocessor">#include &quot;<a class="code" href="../../d4/dd5/highgui_8hpp.html">opencv2/highgui.hpp</a>&quot;</span></div><div class="line"><span class="preprocessor">#include &quot;<a class="code" href="../../d5/d0d/features2d_8hpp.html">opencv2/features2d.hpp</a>&quot;</span></div><div class="line"><span class="preprocessor">#include &quot;<a class="code" href="../../dc/daa/xfeatures2d_8hpp.html">opencv2/xfeatures2d.hpp</a>&quot;</span></div><div class="line"></div><div class="line"><span class="keyword">using namespace </span><a class="code" href="../../d2/d75/namespacecv.html">cv</a>;</div><div class="line"><span class="keyword">using namespace </span><a class="code" href="../../d3/df6/namespacecv_1_1xfeatures2d.html">cv::xfeatures2d</a>;</div><div class="line"><span class="keyword">using</span> std::cout;</div><div class="line"><span class="keyword">using</span> std::endl;</div><div class="line"></div><div class="line"><span class="keyword">const</span> <span class="keywordtype">char</span>* keys =</div><div class="line">    <span class="stringliteral">&quot;{ help h |                  | Print help message. }&quot;</span></div><div class="line">    <span class="stringliteral">&quot;{ input1 | box.png          | Path to input image 1. }&quot;</span></div><div class="line">    <span class="stringliteral">&quot;{ input2 | box_in_scene.png | Path to input image 2. }&quot;</span>;</div><div class="line"></div><div class="line"><span class="keywordtype">int</span> main( <span class="keywordtype">int</span> argc, <span class="keywordtype">char</span>* argv[] )</div><div class="line">{</div><div class="line">    <a class="code" href="../../d0/d2e/classcv_1_1CommandLineParser.html">CommandLineParser</a> parser( argc, argv, keys );</div><div class="line">    <a class="code" href="../../d3/d63/classcv_1_1Mat.html">Mat</a> img1 = <a class="code" href="../../d4/da8/group__imgcodecs.html#ga288b8b3da0892bd651fce07b3bbd3a56">imread</a>( <a class="code" href="../../d6/dba/group__core__utils__samples.html#ga3a33b00033b46c698ff6340d95569c13">samples::findFile</a>( parser.get&lt;<a class="code" href="../../dc/d84/group__core__basic.html#ga1f6634802eeadfd7245bc75cf3e216c2">String</a>&gt;(<span class="stringliteral">&quot;input1&quot;</span>) ), <a class="code" href="../../d8/d6a/group__imgcodecs__flags.html#gga61d9b0126a3e57d9277ac48327799c80ae29981cfc153d3b0cef5c0daeedd2125">IMREAD_GRAYSCALE</a> );</div><div class="line">    <a class="code" href="../../d3/d63/classcv_1_1Mat.html">Mat</a> img2 = <a class="code" href="../../d4/da8/group__imgcodecs.html#ga288b8b3da0892bd651fce07b3bbd3a56">imread</a>( <a class="code" href="../../d6/dba/group__core__utils__samples.html#ga3a33b00033b46c698ff6340d95569c13">samples::findFile</a>( parser.get&lt;<a class="code" href="../../dc/d84/group__core__basic.html#ga1f6634802eeadfd7245bc75cf3e216c2">String</a>&gt;(<span class="stringliteral">&quot;input2&quot;</span>) ), <a class="code" href="../../d8/d6a/group__imgcodecs__flags.html#gga61d9b0126a3e57d9277ac48327799c80ae29981cfc153d3b0cef5c0daeedd2125">IMREAD_GRAYSCALE</a> );</div><div class="line">    <span class="keywordflow">if</span> ( img1.<a class="code" href="../../d3/d63/classcv_1_1Mat.html#abbec3525a852e77998aba034813fded4">empty</a>() || img2.<a class="code" href="../../d3/d63/classcv_1_1Mat.html#abbec3525a852e77998aba034813fded4">empty</a>() )</div><div class="line">    {</div><div class="line">        cout &lt;&lt; <span class="stringliteral">&quot;Could not open or find the image!\n&quot;</span> &lt;&lt; endl;</div><div class="line">        parser.printMessage();</div><div class="line">        <span class="keywordflow">return</span> -1;</div><div class="line">    }</div><div class="line"></div><div class="line">    <span class="comment">//-- Step 1: Detect the keypoints using SURF Detector, compute the descriptors</span></div><div class="line">    <span class="keywordtype">int</span> minHessian = 400;</div><div class="line">    <a class="code" href="../../dc/d84/group__core__basic.html#ga6395ca871a678020c4a31fadf7e8cc63">Ptr&lt;SURF&gt;</a> detector = <a class="code" href="../../d5/df7/classcv_1_1xfeatures2d_1_1SURF.html#a436553ca44d9a2238761ddbee5b395e5">SURF::create</a>( minHessian );</div><div class="line">    std::vector&lt;KeyPoint&gt; keypoints1, keypoints2;</div><div class="line">    <a class="code" href="../../d3/d63/classcv_1_1Mat.html">Mat</a> descriptors1, descriptors2;</div><div class="line">    detector-&gt;detectAndCompute( img1, <a class="code" href="../../dc/d84/group__core__basic.html#gad9287b23bba2fed753b36ef561ae7346">noArray</a>(), keypoints1, descriptors1 );</div><div class="line">    detector-&gt;detectAndCompute( img2, <a class="code" href="../../dc/d84/group__core__basic.html#gad9287b23bba2fed753b36ef561ae7346">noArray</a>(), keypoints2, descriptors2 );</div><div class="line"></div><div class="line">    <span class="comment">//-- Step 2: Matching descriptor vectors with a FLANN based matcher</span></div><div class="line">    <span class="comment">// Since SURF is a floating-point descriptor NORM_L2 is used</span></div><div class="line">    <a class="code" href="../../dc/d84/group__core__basic.html#ga6395ca871a678020c4a31fadf7e8cc63">Ptr&lt;DescriptorMatcher&gt;</a> matcher = <a class="code" href="../../db/d39/classcv_1_1DescriptorMatcher.html#ab5dc5036569ecc8d47565007fa518257">DescriptorMatcher::create</a>(<a class="code" href="../../db/d39/classcv_1_1DescriptorMatcher.html#af8b6f4acb8f1a9ea6b73bfcb86b80c3baf73d671c6860c24f44b2880a77fadcdc">DescriptorMatcher::FLANNBASED</a>);</div><div class="line">    std::vector&lt; std::vector&lt;DMatch&gt; &gt; knn_matches;</div><div class="line">    matcher-&gt;knnMatch( descriptors1, descriptors2, knn_matches, 2 );</div><div class="line"></div><div class="line">    <span class="comment">//-- Filter matches using the Lowe&#39;s ratio test</span></div><div class="line">    <span class="keyword">const</span> <span class="keywordtype">float</span> ratio_thresh = 0.7f;</div><div class="line">    std::vector&lt;DMatch&gt; good_matches;</div><div class="line">    <span class="keywordflow">for</span> (<span class="keywordtype">size_t</span> i = 0; i &lt; knn_matches.size(); i++)</div><div class="line">    {</div><div class="line">        <span class="keywordflow">if</span> (knn_matches[i][0].distance &lt; ratio_thresh * knn_matches[i][1].distance)</div><div class="line">        {</div><div class="line">            good_matches.push_back(knn_matches[i][0]);</div><div class="line">        }</div><div class="line">    }</div><div class="line"></div><div class="line">    <span class="comment">//-- Draw matches</span></div><div class="line">    <a class="code" href="../../d3/d63/classcv_1_1Mat.html">Mat</a> img_matches;</div><div class="line">    <a class="code" href="../../d4/d5d/group__features2d__draw.html#gad8f463ccaf0dc6f61083abd8717c261a">drawMatches</a>( img1, keypoints1, img2, keypoints2, good_matches, img_matches, <a class="code" href="../../d1/da0/classcv_1_1Scalar__.html#ac1509a4b8454fe7fe29db069e13a2e6f">Scalar::all</a>(-1),</div><div class="line">                 <a class="code" href="../../d1/da0/classcv_1_1Scalar__.html#ac1509a4b8454fe7fe29db069e13a2e6f">Scalar::all</a>(-1), std::vector&lt;char&gt;(), <a class="code" href="../../d4/d5d/group__features2d__draw.html#gga2c2ede79cd5141534ae70a3fd9f324c8a811ff9a659123ff7317ccd1269e59259">DrawMatchesFlags::NOT_DRAW_SINGLE_POINTS</a> );</div><div class="line"></div><div class="line">    <span class="comment">//-- Show detected matches</span></div><div class="line">    <a class="code" href="../../d7/dfc/group__highgui.html#ga453d42fe4cb60e5723281a89973ee563">imshow</a>(<span class="stringliteral">&quot;Good Matches&quot;</span>, img_matches );</div><div class="line"></div><div class="line">    <a class="code" href="../../d7/dfc/group__highgui.html#ga5628525ad33f52eab17feebcfba38bd7">waitKey</a>();</div><div class="line">    <span class="keywordflow">return</span> 0;</div><div class="line">}</div><div class="line"><span class="preprocessor">#else</span></div><div class="line"><span class="keywordtype">int</span> main()</div><div class="line">{</div><div class="line">    std::cout &lt;&lt; <span class="stringliteral">&quot;This tutorial code needs the xfeatures2d contrib module to be run.&quot;</span> &lt;&lt; std::endl;</div><div class="line">    <span class="keywordflow">return</span> 0;</div><div class="line">}</div><div class="line"><span class="preprocessor">#endif</span></div></div><!-- fragment -->  </div>  <div class='newInnerHTML' title='java' style='display: none;'>Java</div><div class='toggleable_div label_java' style='display: none;'><p> This tutorial code's is shown lines below. You can also download it from <a href="https://github.com/opencv/opencv/tree/master/samples/java/tutorial_code/features2D/feature_flann_matcher/SURFFLANNMatchingDemo.java">here</a> </p><div class="fragment"><div class="line"><span class="keyword">import</span> java.util.ArrayList;</div><div class="line"><span class="keyword">import</span> java.util.List;</div><div class="line"></div><div class="line"><span class="keyword">import</span> org.opencv.core.Core;</div><div class="line"><span class="keyword">import</span> org.opencv.core.DMatch;</div><div class="line"><span class="keyword">import</span> org.opencv.core.Mat;</div><div class="line"><span class="keyword">import</span> org.opencv.core.MatOfByte;</div><div class="line"><span class="keyword">import</span> org.opencv.core.MatOfDMatch;</div><div class="line"><span class="keyword">import</span> org.opencv.core.MatOfKeyPoint;</div><div class="line"><span class="keyword">import</span> org.opencv.core.Scalar;</div><div class="line"><span class="keyword">import</span> org.opencv.features2d.DescriptorMatcher;</div><div class="line"><span class="keyword">import</span> org.opencv.features2d.Features2d;</div><div class="line"><span class="keyword">import</span> org.opencv.highgui.HighGui;</div><div class="line"><span class="keyword">import</span> org.opencv.imgcodecs.Imgcodecs;</div><div class="line"><span class="keyword">import</span> org.opencv.xfeatures2d.SURF;</div><div class="line"></div><div class="line"><span class="keyword">class </span>SURFFLANNMatching {</div><div class="line">    <span class="keyword">public</span> <span class="keywordtype">void</span> run(<a class="code" href="../../dc/d84/group__core__basic.html#ga1f6634802eeadfd7245bc75cf3e216c2">String</a>[] args) {</div><div class="line">        <a class="code" href="../../dc/d84/group__core__basic.html#ga1f6634802eeadfd7245bc75cf3e216c2">String</a> filename1 = args.length &gt; 1 ? args[0] : <span class="stringliteral">&quot;../data/box.png&quot;</span>;</div><div class="line">        <a class="code" href="../../dc/d84/group__core__basic.html#ga1f6634802eeadfd7245bc75cf3e216c2">String</a> filename2 = args.length &gt; 1 ? args[1] : <span class="stringliteral">&quot;../data/box_in_scene.png&quot;</span>;</div><div class="line">        Mat img1 = Imgcodecs.imread(filename1, Imgcodecs.IMREAD_GRAYSCALE);</div><div class="line">        Mat img2 = Imgcodecs.imread(filename2, Imgcodecs.IMREAD_GRAYSCALE);</div><div class="line">        <span class="keywordflow">if</span> (img1.empty() || img2.empty()) {</div><div class="line">            System.err.println(<span class="stringliteral">&quot;Cannot read images!&quot;</span>);</div><div class="line">            System.exit(0);</div><div class="line">        }</div><div class="line"></div><div class="line">        <span class="comment">//-- Step 1: Detect the keypoints using SURF Detector, compute the descriptors</span></div><div class="line">        <span class="keywordtype">double</span> hessianThreshold = 400;</div><div class="line">        <span class="keywordtype">int</span> nOctaves = 4, nOctaveLayers = 3;</div><div class="line">        <span class="keywordtype">boolean</span> extended = <span class="keyword">false</span>, upright = <span class="keyword">false</span>;</div><div class="line">        SURF detector = SURF.<a class="code" href="../../d3/d63/classcv_1_1Mat.html#a55ced2c8d844d683ea9a725c60037ad0">create</a>(hessianThreshold, nOctaves, nOctaveLayers, extended, upright);</div><div class="line">        MatOfKeyPoint keypoints1 = <span class="keyword">new</span> MatOfKeyPoint(), keypoints2 = <span class="keyword">new</span> MatOfKeyPoint();</div><div class="line">        Mat descriptors1 = <span class="keyword">new</span> Mat(), descriptors2 = <span class="keyword">new</span> Mat();</div><div class="line">        detector.detectAndCompute(img1, <span class="keyword">new</span> Mat(), keypoints1, descriptors1);</div><div class="line">        detector.detectAndCompute(img2, <span class="keyword">new</span> Mat(), keypoints2, descriptors2);</div><div class="line"></div><div class="line">        <span class="comment">//-- Step 2: Matching descriptor vectors with a FLANN based matcher</span></div><div class="line">        <span class="comment">// Since SURF is a floating-point descriptor NORM_L2 is used</span></div><div class="line">        DescriptorMatcher matcher = DescriptorMatcher.create(DescriptorMatcher.FLANNBASED);</div><div class="line">        List&lt;MatOfDMatch&gt; knnMatches = <span class="keyword">new</span> ArrayList&lt;&gt;();</div><div class="line">        matcher.knnMatch(descriptors1, descriptors2, knnMatches, 2);</div><div class="line"></div><div class="line">        <span class="comment">//-- Filter matches using the Lowe&#39;s ratio test</span></div><div class="line">        <span class="keywordtype">float</span> ratioThresh = 0.7f;</div><div class="line">        List&lt;DMatch&gt; listOfGoodMatches = <span class="keyword">new</span> ArrayList&lt;&gt;();</div><div class="line">        <span class="keywordflow">for</span> (<span class="keywordtype">int</span> i = 0; i &lt; knnMatches.size(); i++) {</div><div class="line">            <span class="keywordflow">if</span> (knnMatches.get(i).rows() &gt; 1) {</div><div class="line">                DMatch[] matches = knnMatches.get(i).toArray();</div><div class="line">                <span class="keywordflow">if</span> (matches[0].distance &lt; ratioThresh * matches[1].distance) {</div><div class="line">                    listOfGoodMatches.add(matches[0]);</div><div class="line">                }</div><div class="line">            }</div><div class="line">        }</div><div class="line">        MatOfDMatch goodMatches = <span class="keyword">new</span> MatOfDMatch();</div><div class="line">        goodMatches.fromList(listOfGoodMatches);</div><div class="line"></div><div class="line">        <span class="comment">//-- Draw matches</span></div><div class="line">        Mat imgMatches = <span class="keyword">new</span> Mat();</div><div class="line">        Features2d.drawMatches(img1, keypoints1, img2, keypoints2, goodMatches, imgMatches, <a class="code" href="../../dc/d84/group__core__basic.html#ga599fe92e910c027be274233eccad7beb">Scalar</a>.<a class="code" href="../../d1/da0/classcv_1_1Scalar__.html#ac1509a4b8454fe7fe29db069e13a2e6f">all</a>(-1),</div><div class="line">                <a class="code" href="../../dc/d84/group__core__basic.html#ga599fe92e910c027be274233eccad7beb">Scalar</a>.<a class="code" href="../../d1/da0/classcv_1_1Scalar__.html#ac1509a4b8454fe7fe29db069e13a2e6f">all</a>(-1), <span class="keyword">new</span> MatOfByte(), Features2d.DrawMatchesFlags_NOT_DRAW_SINGLE_POINTS);</div><div class="line"></div><div class="line">        <span class="comment">//-- Show detected matches</span></div><div class="line">        HighGui.imshow(<span class="stringliteral">&quot;Good Matches&quot;</span>, imgMatches);</div><div class="line">        HighGui.waitKey(0);</div><div class="line"></div><div class="line">        System.exit(0);</div><div class="line">    }</div><div class="line">}</div><div class="line"></div><div class="line"><span class="keyword">public</span> <span class="keyword">class </span>SURFFLANNMatchingDemo {</div><div class="line">    <span class="keyword">public</span> <span class="keyword">static</span> <span class="keywordtype">void</span> main(<a class="code" href="../../dc/d84/group__core__basic.html#ga1f6634802eeadfd7245bc75cf3e216c2">String</a>[] args) {</div><div class="line">        <span class="comment">// Load the native OpenCV library</span></div><div class="line">        System.loadLibrary(Core.NATIVE_LIBRARY_NAME);</div><div class="line"></div><div class="line">        <span class="keyword">new</span> SURFFLANNMatching().run(args);</div><div class="line">    }</div><div class="line">}</div></div><!-- fragment -->  </div>  <div class='newInnerHTML' title='python' style='display: none;'>Python</div><div class='toggleable_div label_python' style='display: none;'><p> This tutorial code's is shown lines below. You can also download it from <a href="https://github.com/opencv/opencv/tree/master/samples/python/tutorial_code/features2D/feature_flann_matcher/SURF_FLANN_matching_Demo.py">here</a> </p><div class="fragment"><div class="line"><span class="keyword">from</span> __future__ <span class="keyword">import</span> print_function</div><div class="line"><span class="keyword">import</span> cv2 <span class="keyword">as</span> cv</div><div class="line"><span class="keyword">import</span> numpy <span class="keyword">as</span> np</div><div class="line"><span class="keyword">import</span> argparse</div><div class="line"></div><div class="line">parser = argparse.ArgumentParser(description=<span class="stringliteral">&#39;Code for Feature Matching with FLANN tutorial.&#39;</span>)</div><div class="line">parser.add_argument(<span class="stringliteral">&#39;--input1&#39;</span>, help=<span class="stringliteral">&#39;Path to input image 1.&#39;</span>, default=<span class="stringliteral">&#39;box.png&#39;</span>)</div><div class="line">parser.add_argument(<span class="stringliteral">&#39;--input2&#39;</span>, help=<span class="stringliteral">&#39;Path to input image 2.&#39;</span>, default=<span class="stringliteral">&#39;box_in_scene.png&#39;</span>)</div><div class="line">args = parser.parse_args()</div><div class="line"></div><div class="line">img1 = <a class="code" href="../../d4/da8/group__imgcodecs.html#ga288b8b3da0892bd651fce07b3bbd3a56">cv.imread</a>(<a class="code" href="../../d6/dba/group__core__utils__samples.html#ga3a33b00033b46c698ff6340d95569c13">cv.samples.findFile</a>(args.input1), cv.IMREAD_GRAYSCALE)</div><div class="line">img2 = <a class="code" href="../../d4/da8/group__imgcodecs.html#ga288b8b3da0892bd651fce07b3bbd3a56">cv.imread</a>(<a class="code" href="../../d6/dba/group__core__utils__samples.html#ga3a33b00033b46c698ff6340d95569c13">cv.samples.findFile</a>(args.input2), cv.IMREAD_GRAYSCALE)</div><div class="line"><span class="keywordflow">if</span> img1 <span class="keywordflow">is</span> <span class="keywordtype">None</span> <span class="keywordflow">or</span> img2 <span class="keywordflow">is</span> <span class="keywordtype">None</span>:</div><div class="line">    <a class="code" href="../../df/d57/namespacecv_1_1dnn.html#a701210a0203f2786cbfd04b2bd56da47">print</a>(<span class="stringliteral">&#39;Could not open or find the images!&#39;</span>)</div><div class="line">    exit(0)</div><div class="line"></div><div class="line"><span class="comment">#-- Step 1: Detect the keypoints using SURF Detector, compute the descriptors</span></div><div class="line">minHessian = 400</div><div class="line">detector = cv.xfeatures2d_SURF.create(hessianThreshold=minHessian)</div><div class="line">keypoints1, descriptors1 = detector.detectAndCompute(img1, <span class="keywordtype">None</span>)</div><div class="line">keypoints2, descriptors2 = detector.detectAndCompute(img2, <span class="keywordtype">None</span>)</div><div class="line"></div><div class="line"><span class="comment">#-- Step 2: Matching descriptor vectors with a FLANN based matcher</span></div><div class="line"><span class="comment"># Since SURF is a floating-point descriptor NORM_L2 is used</span></div><div class="line">matcher = cv.DescriptorMatcher_create(cv.DescriptorMatcher_FLANNBASED)</div><div class="line">knn_matches = matcher.knnMatch(descriptors1, descriptors2, 2)</div><div class="line"></div><div class="line"><span class="comment">#-- Filter matches using the Lowe&#39;s ratio test</span></div><div class="line">ratio_thresh = 0.7</div><div class="line">good_matches = []</div><div class="line"><span class="keywordflow">for</span> m,n <span class="keywordflow">in</span> knn_matches:</div><div class="line">    <span class="keywordflow">if</span> m.distance &lt; ratio_thresh * n.distance:</div><div class="line">        good_matches.append(m)</div><div class="line"></div><div class="line"><span class="comment">#-- Draw matches</span></div><div class="line">img_matches = np.empty((<a class="code" href="../../d1/d10/classcv_1_1MatExpr.html#a6dff8b6e9105b6d817b493e7be157c90">max</a>(img1.shape[0], img2.shape[0]), img1.shape[1]+img2.shape[1], 3), dtype=np.uint8)</div><div class="line"><a class="code" href="../../d4/d5d/group__features2d__draw.html#ga62fbedb5206ab2faf411797e7055c90f">cv.drawMatches</a>(img1, keypoints1, img2, keypoints2, good_matches, img_matches, flags=cv.DrawMatchesFlags_NOT_DRAW_SINGLE_POINTS)</div><div class="line"></div><div class="line"><span class="comment">#-- Show detected matches</span></div><div class="line"><a class="code" href="../../df/d24/group__highgui__opengl.html#gaae7e90aa3415c68dba22a5ff2cefc25d">cv.imshow</a>(<span class="stringliteral">&#39;Good Matches&#39;</span>, img_matches)</div><div class="line"></div><div class="line"><a class="code" href="../../d7/dfc/group__highgui.html#ga5628525ad33f52eab17feebcfba38bd7">cv.waitKey</a>()</div></div><!-- fragment -->  </div> <h2>Explanation </h2>
<h2>Result </h2>
<ul>
<li><p class="startli">Here is the result of the SURF feature matching using the distance ratio test:</p>
<div class="image">
<img src="../../Feature_FlannMatcher_Result_ratio_test.jpg" alt="Feature_FlannMatcher_Result_ratio_test.jpg"/>
</div>
 </li>
</ul>
</div></div><!-- contents -->
<!-- HTML footer for doxygen 1.8.6-->
<!-- start footer part -->
<hr class="footer"/><address class="footer"><small>
Generated on Fri Apr 2 2021 11:36:34 for OpenCV by &#160;<a href="http://www.doxygen.org/index.html">
<img class="footer" src="../../doxygen.png" alt="doxygen"/>
</a> 1.8.13
</small></address>
<script type="text/javascript">
//<![CDATA[
addTutorialsButtons();
//]]>
</script>
</body>
</html>
